home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / map / map.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-12  |  24.9 KB  |  755 lines

  1. /*
  2.  *      map.c
  3.  *
  4.  *      This program draws three types of map projections - Perspective,
  5.  *      Modified Perspective, and Azimuthal Equidistant on IBM PC's.
  6.  *
  7.  *      Version 2.7, 7 April 1991
  8.  *      by Steve R. Sampson, N5OWK
  9.  *
  10.  *      Based on a program and article by William D. Johnston
  11.  *      Copyright (c) May-June 1979 BYTE, All Rights Reserved
  12.  *
  13.  *      Compiled using Borland C++
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <conio.h>
  18. #include <fcntl.h>
  19. #include <dos.h>
  20. #include <math.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <graphics.h>
  24.  
  25. typedef char     bool;
  26.  
  27. /* Program Constants */
  28.  
  29. #define FALSE   (bool) 0
  30. #define TRUE    (bool) (!FALSE)
  31.  
  32. #define PI      (3.141593F)        /* That good old constant         */
  33. #define HALFPI  (1.570796F)        /* How about 90 Degrees...         */
  34. #define TWOPI   (2.0F * PI)             /* Two Pi - alias 360 Degrees        */
  35. #define RADIAN  (180.0F / PI)           /* One radian                        */
  36. #define TWO     (2.0F / RADIAN)         /* 2 Degrees in radians              */
  37. #define TEN     (10.0F / RADIAN)        /* 10 degrees in radians             */
  38. #define EIGHTY  (80.0F / RADIAN)        /* 80 degrees in radians             */
  39. #define EARTH   (6378.0F)               /* Mean radius of earth (Kilometers) */
  40.  
  41. /* Program Globals */
  42.  
  43. FILE    *fp;
  44.  
  45. struct  {                               /* Binary Database Format            */
  46.         int     code, lat, lon;
  47. } coord;
  48.  
  49. float   Angle, maxplot, Center_lat, Center_lon, lat, lon, distance,
  50.         sin_of_distance, cos_of_distance, sin_of_center_lat, cos_of_center_lat,
  51.         scale, g, h2, facing_azimuth, aspect;
  52.  
  53. int     Option, Center_x, Center_y, Grid_color, Level = 5;
  54. int     GraphDriver = DETECT, GraphMode;
  55.  
  56. char    EscapeTxt[] = "Press ESC to exit, any key to continue";
  57.  
  58. char    optstring[] = "bcd:gilm:rsxy?";
  59. char    database[128] = "mwdbii";       /* default name 'MWDBII'             */
  60.                                         /* leave room for pathname           */
  61. bool    boundaries = TRUE,              /* defaults to Boundaries, Islands   */
  62.         countries  = FALSE,
  63.         grids      = FALSE,
  64.         islands    = TRUE,
  65.         lakes      = FALSE,
  66.         rivers     = FALSE,
  67.         states     = FALSE,
  68.         colors     = FALSE;
  69.  
  70. /* Forward Declarations, Prototypes */
  71.  
  72. extern  int     directvideo;
  73.  
  74. extern  int     getopt(int, char **, char *);
  75. extern  int     optind, opterr;
  76. extern  char    *optarg;
  77.  
  78. static double    dm2dec(double);
  79. static void    grid(void), plotmap(void), prompts(void), query(void);
  80. static bool    compute(float *, float *, int *, int *), move(int);
  81. static int    quit(void);
  82.  
  83. void main(argc, argv)
  84. int     argc;
  85. char    *argv[];
  86. {
  87.         int    i, err, xasp, yasp;
  88.  
  89.         registerbgidriver(EGAVGA_driver);       /* IBM Drivers               */
  90.         registerbgidriver(Herc_driver);
  91.         registerbgidriver(CGA_driver);
  92.         registerbgifont(small_font);
  93.  
  94.         setcbrk(TRUE);          /* Allow Control-C checking                  */
  95.     ctrlbrk(quit);        /* Execute quit() if Control-C detected      */
  96.  
  97.         while ((i = getopt(argc, argv, optstring)) != -1)  {
  98.                 switch (i)  {
  99.                 case 'b':
  100.                         boundaries = FALSE;
  101.                         break;
  102.                 case 'c':
  103.                         countries = TRUE;
  104.                         break;
  105.                 case 'd':
  106.                         strcpy(database, optarg);
  107.                         break;
  108.                 case 'g':
  109.                         grids = TRUE;
  110.                         break;
  111.                 case 'i':
  112.                         islands = FALSE;
  113.                         break;
  114.                 case 'l':
  115.                         lakes = TRUE;
  116.                         break;
  117.                 case 'm':
  118.                         Level = atoi(optarg);
  119.                         break;
  120.                 case 'r':
  121.                         rivers = TRUE;
  122.                         break;
  123.                 case 's':
  124.                         states = TRUE;
  125.                         break;
  126.                 case 'x':
  127.                         colors = TRUE;
  128.                         break;
  129.                 case 'y':
  130.                         directvideo = 0;
  131.                         break;
  132.                 case '?':
  133.                 default:
  134.                       printf("Usage: map [/bcdgilmrsxy]\n\n");
  135.                       printf("  /b   Boundaries Off\n");
  136.                       printf("  /c   Countries On\n");
  137.                       printf("  /dn  Database ('MWDBII' Default)\n");
  138.                       printf("  /g   Grid lines On\n");
  139.                       printf("  /i   Islands Off\n");
  140.                       printf("  /l   Lakes On\n");
  141.                       printf("  /mn  Map Resolution (5 Default)\n");
  142.                       printf("  /r   Rivers On\n");
  143.                       printf("  /s   States On\n");
  144.                       printf("  /x   Colors On\n");
  145.                       printf("  /y   BIOS Video Mode On\n\n");
  146.                       printf("Defaults to Boundaries and Islands On\n");
  147.  
  148.                       exit(0);
  149.                 }
  150.         }
  151.  
  152.         if ((fp = fopen(database, "rb")) == (FILE *)NULL)  {
  153.                 printf("\007Error: Can't locate Database '%s'\n", database);
  154.                 exit(1);
  155.         }
  156.  
  157.         setvbuf(fp,  NULL, _IOFBF, 32767);
  158.  
  159.         initgraph(&GraphDriver, &GraphMode, "");/* initialize graphics       */
  160.         err = graphresult();
  161.  
  162.         if (err < 0)  {
  163.                 printf("Graphics Error - %s\n", grapherrormsg(err));
  164.                 exit(1);
  165.         }
  166.  
  167.         if (GraphMode == VGAHI)  {              /* Use medium resolution     */
  168.                 GraphMode = VGAMED;             /*   for 2 graphic pages     */
  169.                 setgraphmode(GraphMode);        /*   and then enable it      */
  170.         }
  171.  
  172.         Center_x = getmaxx() / 2;               /* get screen size for x, y  */
  173.         Center_y = getmaxy() / 2;
  174.         getaspectratio(&xasp, &yasp);           /* squish factor for y axis  */
  175.         aspect = (float)xasp / (float)yasp;
  176.  
  177.         restorecrtmode();                       /* get back to text mode     */
  178.         prompts();                              /* get the basic map info    */
  179.  
  180.         setgraphmode(GraphMode);                /*  and go to graphics mode  */
  181.  
  182.         if ((GraphMode == CGAHI) || (GraphMode == HERCMONOHI))
  183.                 Grid_color = LIGHTGRAY;         /* CGA/HERC has two colors   */
  184.         else  {
  185.                 setbkcolor(EGA_BLACK);          /* must be EGA or VGA then   */
  186.                 if (colors)
  187.                         Grid_color = EGA_CYAN;
  188.                 else
  189.                         Grid_color = EGA_LIGHTGRAY;
  190.         }
  191.  
  192.         if (grids)
  193.                 grid();                         /* draw lat & long ref lines */
  194.  
  195.         setcolor(LIGHTGRAY);
  196.  
  197.         /*
  198.          *      See if data plotting is even needed
  199.          */
  200.  
  201.         if (boundaries || islands || countries || lakes || rivers || states)
  202.                 plotmap();                      /* display map on screen     */
  203.  
  204.         setcolor(LIGHTGRAY);
  205.         outtextxy(0, getmaxy() - 10, "Done");
  206.         getch();                                /* wait for end of viewing   */
  207.  
  208.         quit();
  209. }
  210.  
  211. /*
  212.  *      Return to operator
  213.  */
  214.  
  215. #pragma warn -rvl
  216. static int quit()
  217. {
  218.         closegraph();                           /* graphics off              */
  219.         fclose(fp);                             /* close database file       */
  220.  
  221.         exit(0);
  222. }
  223. #pragma warn +rvl
  224.  
  225. /*
  226.  *      Operator prompts and input.
  227.  */
  228.  
  229. static void prompts()
  230. {
  231.         float   ret, altitude;
  232.  
  233.         printf("West Longitudes and South Latitudes are negative\n");
  234.  
  235.         /* input the world Lat & Long that is to be centered on */
  236.         /*   then convert the human notation to radians         */
  237.  
  238.         do  {
  239.                 printf("\nLatitude of the map center [+-]dd.mm : ");
  240.                 scanf("%f", &ret);
  241.                 ret = dm2dec(ret);
  242.         } while (ret > 90.0F || ret < -90.0F);
  243.  
  244.         /* the arcosine function has trouble at 90 degrees */
  245.  
  246.         if (ret == 90.0F)
  247.                 Center_lat = 89.9F / RADIAN;
  248.         else if (ret == -90.0F)
  249.                 Center_lat = -89.9F / RADIAN;
  250.         else
  251.                 Center_lat = ret / RADIAN;
  252.  
  253.         sin_of_center_lat = sin(Center_lat);
  254.         cos_of_center_lat = cos(Center_lat);
  255.  
  256.         do  {
  257.                 printf("Longitude of the map center [+-]ddd.mm : ");
  258.                 scanf("%f", &ret);
  259.                 ret = dm2dec(ret);
  260.         } while (ret > 180.0F || ret < -180.0F);
  261.  
  262.         Center_lon = ret / RADIAN;
  263.  
  264.         do  {
  265.                 printf("\nSelect from the following options:\n\n");
  266.                 printf("  1 - Perspective Projection\n");
  267.                 printf("  2 - Modified Perspective Projection\n");
  268.                 printf("  3 - Azimuthal Equidistant Projection\n\n");
  269.                 printf("Choice : ");
  270.                 scanf("%d", &Option);
  271.         } while (Option < 1 || Option > 3);
  272.  
  273.         if (Option == 3)  {
  274.                 /* input the radial distance to map */
  275.  
  276.                 do  {
  277.                         printf("\nArc Distance (1 - 180 degrees) : ");
  278.                         scanf("%f", &maxplot);
  279.                 } while (maxplot == 0.0F || maxplot > 180.0F);
  280.  
  281.                 maxplot /= RADIAN;
  282.                 scale = (float) Center_y / maxplot;
  283.                 return;
  284.         }
  285.  
  286.         /* input the height above the terrain */
  287.  
  288.         printf("\nObserver altitude (km) : ");
  289.         scanf("%f", &altitude);
  290.  
  291.         if (altitude == 0.0F)
  292.                 altitude = 1.0F;
  293.  
  294.         h2 = EARTH + altitude;
  295.         maxplot = acos(EARTH / h2);
  296.  
  297.         /* The operator can orient the world upside down if they want */
  298.  
  299.         do  {
  300.                 printf("Observer facing azimuth (0 - 359 degrees) : ");
  301.                 scanf("%f", &facing_azimuth);
  302.         } while (facing_azimuth < 0.0F || facing_azimuth > 360.0F);
  303.  
  304.         facing_azimuth = -facing_azimuth / RADIAN;
  305.  
  306.         /* Calculate the scale for the polar coordinates */
  307.  
  308.         scale = (float)Center_y / (EARTH * sin(maxplot));
  309.  
  310.         /* For the perspective projection */
  311.  
  312.         g = EARTH * (h2 - EARTH * cos(maxplot));
  313. }
  314.  
  315. /*
  316.  *      Convert the database to the desired projection by computation.
  317.  *
  318.  *      This code is a hand translation from BASIC to C based on Mr. Johnstons
  319.  *      code.  It is a non-mathematicians idea of what he meant.
  320.  *
  321.  *      Return TRUE if offscale else FALSE.
  322.  */
  323.  
  324. static bool compute(lat, lon, x, y)
  325. float   *lat, *lon;
  326. int    *x, *y;
  327. {
  328.         float   sin_of_lat,
  329.                 cos_of_lat,
  330.                 abs_delta_lon,                  /* absolute value            */
  331.                 delta_lon,                      /* x distance from center    */
  332.                 delta_lat,                      /* y distance from center    */
  333.                 temp;                           /* temporary storage         */
  334.  
  335.         /* normalize the longitude to +/- PI */
  336.  
  337.         delta_lon = *lon - Center_lon;
  338.  
  339.         if (delta_lon < -PI)
  340.                 delta_lon = delta_lon + TWOPI;
  341.  
  342.         if (delta_lon > PI)
  343.                 delta_lon = delta_lon - TWOPI;
  344.  
  345.         abs_delta_lon = fabs(delta_lon);
  346.  
  347.         /*
  348.          *      If the delta_lon is within .00015 radians of 0 then
  349.          *      the difference is considered exactly zero.
  350.          *
  351.          *      This also simplifies the great circle bearing calculation.
  352.          */
  353.  
  354.         if (abs_delta_lon <= 0.00015F)  {
  355.                 delta_lat = fabs(Center_lat - *lat);
  356.  
  357.                 if (delta_lat > maxplot)
  358.                         return TRUE;            /* offscale                  */
  359.  
  360.                 if (*lat < Center_lat)
  361.                         Angle = PI;
  362.                 else
  363.                         Angle = 0.0F;
  364.  
  365.                 sin_of_distance = sin(delta_lat);
  366.                 cos_of_distance = cos(delta_lat);
  367.         }
  368.  
  369.         /*
  370.          *      Check if delta_lon is within .00015 radians of PI.
  371.          */
  372.  
  373.         else if (fabs(PI - abs_delta_lon) <= 0.00015F)  {
  374.                 delta_lat = PI - Center_lat - *lat;
  375.  
  376.                 if (delta_lat > PI)  {
  377.                         delta_lat = TWOPI - delta_lat;
  378.                         Angle = PI;
  379.                 } else
  380.                         Angle = 0.0F;
  381.  
  382.                 if (delta_lat > maxplot)
  383.                         return TRUE;            /* offscale                  */
  384.  
  385.                 sin_of_distance = sin(delta_lat);
  386.                 cos_of_distance = cos(delta_lat);
  387.         }
  388.  
  389.         /*
  390.          *      Simple calculations are out, now get cosmic.
  391.          */
  392.  
  393.         else  {
  394.                 sin_of_lat = sin(*lat);
  395.                 cos_of_lat = cos(*lat);
  396.  
  397.                 cos_of_distance = sin_of_center_lat * sin_of_lat +
  398.                                     cos_of_center_lat * cos_of_lat *
  399.                                       cos(delta_lon);
  400.  
  401.                 distance = acos(cos_of_distance);
  402.  
  403.                 if (distance > maxplot)
  404.                         return TRUE;            /* offscale                  */
  405.  
  406.                 sin_of_distance = sin(distance);
  407.  
  408.                 temp = (sin_of_lat - sin_of_center_lat * cos_of_distance) /
  409.                         (cos_of_center_lat * sin_of_distance);
  410.  
  411.                 if (temp < -1.0F || temp > 1.0F)
  412.                         return TRUE;            /* offscale                  */
  413.  
  414.                 Angle = acos(temp);
  415.  
  416.                 if (delta_lon < 0.0F)
  417.                         Angle = TWOPI - Angle;
  418.         }
  419.  
  420.         if (facing_azimuth != 0.0F)  {
  421.                 Angle = Angle - facing_azimuth;
  422.                 if (Angle < 0.0F)
  423.                         Angle = TWOPI + Angle;
  424.         }
  425.  
  426.         Angle = HALFPI - Angle;
  427.  
  428.         if (Angle < -PI)
  429.                 Angle = Angle + TWOPI;
  430.  
  431.         switch (Option)  {
  432.         case 1:
  433.                 temp  = (scale * (g * sin_of_distance)) /
  434.                                 (h2 - EARTH * cos_of_distance);
  435.                 break;
  436.         case 2:
  437.                 temp = scale * EARTH * sin_of_distance;
  438.                 break;
  439.         case 3:
  440.                 temp = scale * distance;
  441.         }
  442.  
  443.         /* convert polar to rectangular, correct for screen aspect */
  444.  
  445.         *x = Center_x + (int)(temp * cos(Angle));
  446.         *y = Center_y - (int)(temp * sin(Angle) * aspect);
  447.  
  448.         return FALSE;
  449. }
  450.  
  451. /*
  452.  *      Read the database and plot points or lines.
  453.  */
  454.  
  455. static void plotmap()
  456. {
  457.         float   lat, lon;
  458.         int     x, y;
  459.         bool    point;
  460.  
  461.         point = TRUE;
  462.         while (fread(&coord, sizeof coord, 1, fp) > 0)  {
  463.                 if (kbhit())  {
  464.                         getch();
  465.                         query();
  466.                 }
  467.  
  468.                 /*
  469.                  *      Skip data that has been optioned out.
  470.                  */
  471.  
  472.                 if (coord.code < Level)
  473.                         continue;
  474.  
  475.                 if (coord.code > 5)  {          /* must be a header          */
  476.                         point = TRUE;
  477.  
  478.                         switch (coord.code / 1000)  {
  479.                         case 1:
  480.                                 if (boundaries)  {
  481.                                         if (colors)
  482.                                                 setcolor(EGA_LIGHTGRAY);
  483.                                         break;
  484.                                 } else  {
  485.                                         if (move(1))
  486.                                                 return;
  487.                                         continue;
  488.                                 }
  489.                         case 2:
  490.                                 if (countries)  {
  491.                                         if (colors)
  492.                                                 setcolor(EGA_BROWN);
  493.                                         break;
  494.                                 } else  {
  495.                                         if (move(2))
  496.                                                 return;
  497.                                         continue;
  498.                                 }
  499.                         case 4:
  500.                                 if (states)  {
  501.                                         if (colors)
  502.                                                 setcolor(EGA_BROWN);
  503.                                         break;
  504.                                 } else  {
  505.                                         if (move(4))
  506.                                                 return;
  507.                                         continue;
  508.                                 }
  509.                         case 5:
  510.                                 if (islands)  {
  511.                                         if (colors)
  512.                                                 setcolor(EGA_LIGHTGRAY);
  513.                                         break;
  514.                                 } else  {
  515.                                         if (move(5))
  516.                                                 return;
  517.                                         continue;
  518.                                 }
  519.                         case 6:
  520.                                 if (lakes)  {
  521.                                         if (colors)
  522.                                                 setcolor(EGA_BLUE);
  523.                                         break;
  524.                                 } else  {
  525.                                         if (move(6))
  526.                                                 return;
  527.                                         continue;
  528.                                 }
  529.                         case 7:
  530.                                 if (rivers)  {
  531.                                         if (colors)
  532.                                                 setcolor(EGA_GREEN);
  533.                                         break;
  534.                                 } else  {
  535.                                         if (move(7))
  536.                                                 return;
  537.                                         continue;
  538.                                 }
  539.                         }
  540.                 }
  541.  
  542.                 /*  Convert database minutes of a degree to radians */
  543.  
  544.                 lat =  (float) coord.lat / 60.0F / RADIAN;
  545.                 lon =  (float) coord.lon / 60.0F / RADIAN;
  546.  
  547.                 if (compute(&lat, &lon, &x, &y))  {
  548.                         point = TRUE;           /* offscale                  */
  549.                         continue;
  550.                 }
  551.  
  552.                 if (point)  {
  553.                         putpixel(x, y, getcolor());/* put down a dot         */
  554.                         moveto(x, y);
  555.                         point = FALSE;
  556.                 }
  557.                 else
  558.                         lineto(x, y);           /* connect the dots          */
  559.         }
  560. }
  561.  
  562. /*
  563.  *      Move to next database characteristic
  564.  *
  565.  *      Returns TRUE for end of file, else FALSE
  566.  */
  567.  
  568. static bool move(n)
  569. int     n;
  570. {
  571.         while (fread(&coord, sizeof coord, 1, fp) > 0)  {
  572.                 if ((coord.code > 5) && ((coord.code/1000) != n))
  573.                         return FALSE;
  574.         }
  575.  
  576.         return TRUE;
  577. }
  578.  
  579. /*
  580.  *      Convert +-ddd.mm
  581.  *
  582.  *      Change degrees and minutes to decimal
  583.  */
  584.  
  585. static double dm2dec(degmin)
  586. double  degmin;
  587. {
  588.         float  t;
  589.  
  590.         t = (int)degmin;        /* get the integer part */
  591.         degmin -= t;            /* now the fractional part */
  592.         degmin /= .60;          /* convert minutes to decimal */
  593.  
  594.         return (degmin + t);    /* add the two */
  595. }
  596.  
  597. /*
  598.  *      Draw grid lines
  599.  *
  600.  *      Azimuthal Equidistant - Draw a radar scope presentation
  601.  *    on EGA/VGA, regular grid on CGA and HERC - From -180 to
  602.  *    +180 Degrees (Longitude Lines), and +80 to -80 Degrees
  603.  *    (Latitude Lines).
  604.  */
  605.  
  606. static void grid()
  607. {
  608.         int     x, y, pass1;
  609.         float   lat, lon, bearing, t;
  610.  
  611.         setcolor(Grid_color);
  612.  
  613.         if (Option == 3 && GraphMode != CGAHI && GraphMode != HERCMONOHI)  {
  614.         setvisualpage(1);
  615.         setactivepage(0);
  616.  
  617.                 circle(Center_x, Center_y, Center_y);       /* inner ring     */
  618.                 circle(Center_x, Center_y, Center_y+10);   /* outer ring     */
  619.  
  620.                 /*
  621.                  *      Ten Degree Full size ticks
  622.                  */
  623.  
  624.                 t = (float)(Center_y+10);
  625.                 for (bearing = 0.0F; bearing < TWOPI; bearing += TEN)  {
  626.                         moveto(Center_x, Center_y);
  627.                         x = Center_x + (int)(t * sin(bearing));
  628.                         y = Center_y - (int)(t * cos(bearing) * aspect);
  629.                         lineto(x, y);
  630.                 }
  631.  
  632.                 /*
  633.                  *      Two Degree Half size ticks
  634.                  */
  635.  
  636.                 t = (float)(Center_y+5);
  637.                 for (bearing = 0.0F; bearing < TWOPI; bearing += TWO)  {
  638.                         moveto(Center_x, Center_y);
  639.                         x = Center_x + (int)(t * sin(bearing));
  640.                         y = Center_y - (int)(t * cos(bearing) * aspect);
  641.                         lineto(x, y);
  642.                 }
  643.  
  644.                 /*
  645.                  *      This routine erases all bearing lines except
  646.                  *      those between the two circles.
  647.                  */
  648.  
  649.                 setcolor(EGA_WHITE);
  650.                 circle(Center_x, Center_y, Center_y);
  651.  
  652.                 settextjustify(CENTER_TEXT, CENTER_TEXT);
  653.                 setfillstyle(SOLID_FILL, EGA_BLACK);
  654.  
  655.                 floodfill(Center_x, Center_y, EGA_WHITE);
  656.  
  657.                 setcolor(Grid_color);
  658.                 circle(Center_x, Center_y, Center_y);
  659.  
  660.                 /*
  661.                  *      Mark the center
  662.                  */
  663.  
  664.                 outtextxy(Center_x, Center_y, "+");
  665.  
  666.                 /*
  667.                  *      Label the Axis
  668.                  */
  669.  
  670.                 settextstyle(SMALL_FONT, HORIZ_DIR, 4);
  671.  
  672.                 outtextxy(Center_x, 20,  "360");
  673.                 outtextxy(520, Center_y, "090");
  674.                 outtextxy(Center_x, 330, "180");
  675.                 outtextxy(120, Center_y, "270");
  676.  
  677.                 /*
  678.                  *      Return to defaults
  679.                  */
  680.  
  681.                 settextstyle(DEFAULT_FONT, HORIZ_DIR, 1);
  682.                 settextjustify(LEFT_TEXT, LEFT_TEXT);
  683.  
  684.                 setvisualpage(0);
  685.         } else  {
  686.                 setlinestyle(DOTTED_LINE, NULL, NORM_WIDTH);
  687.  
  688.                 for (lon = -PI; lon <= PI; lon += TEN)  {
  689.                         pass1 = TRUE;
  690.                         for (lat = EIGHTY; lat > -EIGHTY; lat -= TEN)  {
  691.                                 if (!compute(&lat, &lon, &x, &y))  {
  692.                                         if (pass1)  {
  693.                                                 putpixel(x, y, Grid_color);
  694.                                                 moveto(x, y);
  695.                                                 pass1 = FALSE;
  696.                                         } else
  697.                                                 lineto(x, y);
  698.                                 } else
  699.                                         pass1 = TRUE;
  700.                         }
  701.  
  702.                         if (kbhit())  {
  703.                                 getch();
  704.                                 query();
  705.                         }
  706.                 }
  707.  
  708.                 for (lat = EIGHTY; lat > -EIGHTY; lat -= TEN)  {
  709.                         pass1 = TRUE;
  710.                         for (lon = -PI; lon <= PI; lon += TEN)  {
  711.                                 if (!compute(&lat, &lon, &x, &y))  {
  712.                                         if (pass1)  {
  713.                                                 putpixel(x, y, Grid_color);
  714.                                                 moveto(x, y);
  715.                                                 pass1 = FALSE;
  716.                                         } else
  717.                                                 lineto(x, y);
  718.                                 } else
  719.                                         pass1 = TRUE;
  720.  
  721.                         }
  722.  
  723.                         if (kbhit())  {
  724.                                 getch();
  725.                                 query();
  726.                         }
  727.                 }
  728.  
  729.                 setlinestyle(SOLID_LINE, NULL, NORM_WIDTH);
  730.         }
  731. }
  732.  
  733. static void query()
  734. {
  735.         int     x, y;
  736.  
  737.         sound(1000);                            /* 1000 Hz for fourth/second */
  738.         delay(250);
  739.         nosound();
  740.  
  741.         x = getx();                             /* remember last location    */
  742.         y = gety();
  743.         outtextxy(0, getmaxy() - 10, EscapeTxt);
  744.  
  745.         if (getch() == '\033')                  /* Escape character?         */
  746.                 quit();
  747.  
  748.         setcolor(BLACK);
  749.         outtextxy(0, getmaxy() - 10, EscapeTxt);
  750.         setcolor(LIGHTGRAY);
  751.         moveto(x, y);                           /* go back to last location  */
  752. }
  753.  
  754. /* That is all */
  755.